﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;
using App.Modelo;
using App.Modelo.Attributes;
using App.Modelo.Config;
using App.Modelo.Interfaces;

namespace App.Seguridad.Vista.Menu
{
    public class PerfilCommandInvoker 
    {
        private Dictionary<string, IList<Type>> _Formularios;

        /// <summary>
        /// Retorna una lista de assemblies donde se buscaran los formularios
        /// </summary>
        private IEnumerable<Assembly> Assemblies
        {
            get
            {
                var cfg = SeguridadConfiguration.GetConfig();
                var list = new List<Assembly>();

                foreach ( ModuloSettingElements m in cfg.Modulos ) {
                    list.Add(Assembly.Load(m.AssemblyName));
                }

                return list;
            }
        }

        /// <summary>
        /// Retorna una diccionario indexado por nombre de formularios encontrados en los assemblies
        /// </summary>
        public Dictionary<string, IList<Type>> Formularios
        {
            get
            {
                // si no esta seteado _Formularios inicializa con los datos del asembly
                // buscando en los attributos
                if (_Formularios == null)
                {
                    _Formularios = new Dictionary<string, IList<Type>>();

                    // rutina que busca todos las clases con el atributo IFormulario
                    foreach (var a in Assemblies)
                    {
                        foreach (var t in a.GetTypes())
                        {
                            foreach (IFormulario p in
                                t.GetCustomAttributes(typeof (IFormulario), true))
                            {
                                if (!Formularios.ContainsKey(p.Nombre))
                                {
                                    Formularios.Add(p.Nombre, new List<Type>());
                                }
                                Formularios[p.Nombre].Add(t);
                            }
                        }
                    }
                }
                return _Formularios;
            }
            set
            {
                _Formularios = value;
            }
        }

        public Form MdiParent { get; set; }

        private IList<Type> GetFormulario(Formulario formulario)
        {
            if (Formularios.ContainsKey(formulario.Nombre))
                return Formularios[formulario.Nombre];

            return new List<Type>();
        }

        private bool ejecutarComandoFormulario(Perfil perfil, Form target)
        {
            foreach (var method in target.GetType().GetMethods()) 
            {
                object[] attrs = method.GetCustomAttributes(typeof(ComandoAttribute), true);

                foreach (ComandoAttribute attr in attrs)
                {
                    if (attr.Nombre == perfil.Funcion.Nombre)
                        try
                        {
                            method.Invoke(target, new object[] { });
                            return true;
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show("No se puede ejecutar la accion\n"+e.ToString());
                            return false;
                        }
                }
            }
            return false;
        }


        /// <summary>
        /// Este metodo instancia un formulario a traves de la informacion alojada en la calse perfil y 
        /// ejecuta su metodo publico para mostrarlo si el usuario tiene los privilegios necesarios
        /// </summary>
        /// <param name="perfil"></param>
        /// <returns>Retorna el formulario instanciado o null si no se encontró</returns>
        public Form EjecutarAccion( Perfil perfil  ) 
        {
            foreach (var tipo in GetFormulario(perfil.Formulario))
            {
                if (tipo != null)
                {
                    var controlador = (Form)tipo.GetConstructor(Type.EmptyTypes).Invoke(null);

                    if (controlador != null)
                    {
                        if (MdiParent != null)
                        {
                            controlador.MdiParent = MdiParent;
                        }

                        if (ejecutarComandoFormulario(perfil, controlador))
                        {
                            return controlador;
                        }
                    }
                }
            }
            
            
            return null;
        }
    }

}
